# File: src/agent/observer.py
# Purpose: Observes the environment state using MCP client.
# (REVISED TO FIX PYRIGHT ERRORS)

import logging
import json
from typing import Optional, Dict, Any

# Use relative imports
from ..mcp_client import get_mcp_session
from ..core.exceptions import AgentError, MCPClientError
from ..schemas.agent import AgentObservation
from ..schemas.mcp.web_automation import PageObservation

# --- 导入 MCP 类型 ---
# 假设环境设置正确，mcp 库已安装，导入应该成功
# 如果导入失败，程序启动时会抛出 ImportError，这是期望的行为，因为 Observer 无法工作
try:
    from mcp import types as mcp_types
    CallToolResult = mcp_types.CallToolResult
    TextContent = mcp_types.TextContent
    # 打印日志确认导入成功
    logging.getLogger(__name__).debug("Successfully imported mcp.types: CallToolResult, TextContent")
except ImportError as e:
    # 记录致命错误并重新抛出，阻止应用启动
    logging.getLogger(__name__).critical("FATAL: Failed to import mcp.types. Ensure 'mcp' library is installed correctly.", exc_info=True)
    raise ImportError("Critical MCP type import failed. Cannot initialize Observer.") from e
# ---------------------

# Use core logger setup
from ..core.logging_setup import get_logger
logger = get_logger(__name__)

class Observer:
    """Handles observing the environment state by interacting with MCP."""

    async def get_observation(self, task_domain: str = "web") -> AgentObservation:
        """Gets the current observation based on the task domain."""
        observer_name = f"Observer({task_domain})"
        logger.info(f"[{observer_name}] Getting observation...")
        # 明确 observation_data 的类型，初始为 None
        observation_data: Optional[PageObservation] = None
        observation_type: str = "unknown"
        observation_summary: Optional[str] = None
        raw_result: Any = None
        # 初始化 parsed_dict 以修复 "possibly unbound" 警告
        parsed_dict: Optional[Dict] = None

        try:
            session = await get_mcp_session()

            if task_domain == "web":
                observation_type = "web_page"
                tool_identifier_name = "observe_page"
                logger.debug(f"[{observer_name}] Calling MCP tool '{tool_identifier_name}'...")

                raw_result = await session.call_tool(name=tool_identifier_name, arguments={})
                logger.debug(f"[{observer_name}] Raw result type from '{tool_identifier_name}': {type(raw_result)}")
                logger.debug(f"[{observer_name}] Raw result content: {getattr(raw_result, 'content', 'N/A')}")

                # --- 解析逻辑 ---
                parsed_successfully = False
                # 由于我们移除了 Any 的后备，这里的 isinstance 类型检查现在是有效的
                if isinstance(raw_result, CallToolResult) and raw_result.content:
                    # 假设第一个 content 项是 TextContent
                    first_content = raw_result.content[0]
                    if isinstance(first_content, TextContent):
                        json_text = first_content.text
                        logger.debug(f"[{observer_name}] Extracted JSON text: {json_text[:200]}...")
                        try:
                            # 解析 JSON
                            parsed_dict = json.loads(json_text) # 赋值给 parsed_dict
                            if isinstance(parsed_dict, dict):
                                # 使用 Pydantic 验证并创建 PageObservation
                                observation_data = PageObservation(**parsed_dict)
                                parsed_successfully = True
                                logger.debug(f"[{observer_name}] Successfully parsed JSON into PageObservation.")
                            else:
                                logger.error(f"[{observer_name}] Parsed JSON is not a dictionary: {type(parsed_dict)}")
                        except json.JSONDecodeError as json_err:
                            logger.error(f"[{observer_name}] Failed to decode JSON from TextContent: {json_err}", exc_info=False)
                            logger.error(f"JSON Text was: {json_text}")
                        except Exception as pydantic_err: # 捕获 Pydantic 验证错误等
                             logger.error(f"[{observer_name}] Failed to validate parsed dict into PageObservation: {pydantic_err}", exc_info=True)
                             # 现在可以安全地记录 parsed_dict，因为它已被初始化
                             logger.error(f"Parsed Dictionary that failed validation was: {parsed_dict}")
                    else:
                        logger.error(f"[{observer_name}] First content item is not TextContent: {type(first_content)}")
                else:
                     # 如果 raw_result 不是 CallToolResult 或 content 为空
                     logger.error(f"[{observer_name}] Result is not CallToolResult or has empty content. Type: {type(raw_result)}")

                # 如果解析失败，抛出 AgentError
                if not parsed_successfully:
                     logger.debug(f"[{observer_name}] Failed to parse observation. Raw result: {raw_result}")
                     raise AgentError(f"Failed to parse expected PageObservation data from tool '{tool_identifier_name}' result.")
                # --- 解析逻辑结束 ---

                # 确保 observation_data 在成功时被赋值
                if observation_data:
                    observation_summary = getattr(observation_data, 'observation_summary', None)
                    obs_error = getattr(observation_data, 'error_message', None)
                    if obs_error:
                        logger.warning(f"[{observer_name}] Observation tool reported an error within data: {obs_error}")
                else:
                    # 此处理论上不应到达，因为解析失败会 raise AgentError
                    logger.error(f"[{observer_name}] Inconsistent state: Parsing reported success, but observation_data is still None.")
                    raise AgentError("Internal observer error: Failed to assign observation data despite apparent parsing success.")


            else: # 处理其他 task_domain
                logger.warning(f"[{observer_name}] Unknown task domain: {task_domain}")
                raise AgentError(f"Cannot observe unknown domain: {task_domain}")

            logger.info(f"[{observer_name}] Observation successful (Type: {observation_type}).")
            # 返回 AgentObservation，其中 data 应该是 PageObservation 对象
            return AgentObservation(
                observation_type=observation_type,
                data=observation_data,
                summary=observation_summary
            )

        # --- 外层异常处理保持不变 ---
        except MCPClientError as e:
            logger.error(f"[{observer_name}] MCP Client error during observation: {e}", exc_info=False)
            raise AgentError(f"MCP client error during observation: {e}") from e
        except AgentError as e:
             logger.error(f"[{observer_name}] Agent error during observation: {e}", exc_info=True)
             logger.debug(f"Raw result at time of AgentError (if available): {raw_result}")
             raise e
        except Exception as e:
            logger.error(f"[{observer_name}] Unexpected error during observation: {e}", exc_info=True)
            logger.debug(f"Raw result at time of unexpected error (if available): {raw_result}")
            raise AgentError(f"Unexpected error during observation: {e}") from e